<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		CodeIgniter
 * @author		ExpressionEngine Dev Team
 * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://codeigniter.com
 * @since		Version 1.0
 * @filesource
 */

// ------------------------------------------------------------------------

/**
 * CodeIgniter Profiler Class
 *
 * This class enables you to display benchmark, query, and other data
 * in order to help with debugging and optimization.
 *
 * Note: At some point it would be good to move all the HTML in this class
 * into a set of template files in order to allow customization.
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author		ExpressionEngine Dev Team
 * @link		http://codeigniter.com/user_guide/general/profiling.html
 */
class CI_Profiler extends CI_Loader {

	var $CI;

	protected $_available_sections = array(
		'benchmarks',
		'get',
		'memory_usage',
		'post',
		'uri_string',
		'controller_info',
		'queries',
		'http_headers',
		'config',
		'files',
		'console',
		'userdata'
	);
	protected $_sections = array();		// Stores _compile_x() results 

	// --------------------------------------------------------------------

	public function __construct($config = array())
	{
		$this->CI =& get_instance();
		
		$config = array_merge($config, config_item('debugbar_sections'));

		// default all sections to display
		foreach ($this->_available_sections as $section)
		{
			$this->_compile_{$section} = !empty($config[$section]);
		}
		
		$this->set_sections($config);
	}

	// --------------------------------------------------------------------

	/**
	 * Set Sections
	 *
	 * Sets the private _compile_* properties to enable/disable Profiler sections
	 *
	 * @param	mixed
	 * @return	void
	 */
	public function set_sections($config)
	{
		foreach ($config as $method => $enable)
		{
			if (in_array($method, $this->_available_sections))
			{
				$this->_compile_{$method} = ($enable !== FALSE) ? TRUE : FALSE;
			}
		}
	}

	// --------------------------------------------------------------------

	/**
	 * Auto Profiler
	 *
	 * This function cycles through the entire array of mark points and
	 * matches any two points that are named identically (ending in "_start"
	 * and "_end" respectively).  It then compiles the execution times for
	 * all points and returns it as an array
	 *
	 * @return	array
	 */
	protected function _compile_benchmarks()
	{
		$profile = array();
		$output = array();
		
		foreach ($this->CI->benchmark->marker as $key => $val)
		{
			// We match the "end" marker so that the list ends
			// up in the order that it was defined
			if (preg_match("/(.+?)_end/i", $key, $match))
			{
				if (isset($this->CI->benchmark->marker[$match[1].'_end']) AND isset($this->CI->benchmark->marker[$match[1].'_start']))
				{
					$profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key);
				}
			}
		}

		// Build a table containing the profile data.
		// Note: At some point we might want to make this data available to be logged.

		foreach ($profile as $key => $val)
		{
			$key = ucwords(str_replace(array('_', '-'), ' ', $key));
			$output[$key] = $val;
		}

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Compile Queries
	 *
	 * @return	string
	 */
	protected function _compile_queries()
	{
		$dbs = array();
		$output = array();

		// Let's determine which databases are currently connected to
		foreach (get_object_vars($this->CI) as $CI_object)
		{
			if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB') )
			{
				$dbs[] = $CI_object;
			}
		}

		if (count($dbs) == 0)
		{
			return $this->CI->lang->line('profiler_no_db');
		}

		// Load the text helper so we can highlight the SQL
		$this->CI->load->helper('text');

		foreach ($dbs as $db)
		{
			if (count($db->queries) == 0)
			{
				$output = $this->CI->lang->line('profiler_no_queries');
			}
			else
			{
				foreach ($db->queries as $key => $val)
				{
					$time = number_format($db->query_times[$key], 4);
					
					$val = highlight_code($val, ENT_QUOTES);
					
					$output[] = array($time, $val);
				}
			}

		}

		return $output;
	}


	// --------------------------------------------------------------------

	/**
	 * Compile $_GET Data
	 *
	 * @return	string
	 */
	protected function _compile_get()
	{
		$output = array();
			
		if (count($_GET) == 0)
		{
			$output = $this->CI->lang->line('profiler_no_get');
		}
		else
		{
			foreach ($_GET as $key => $val)
			{
				if ( ! is_numeric($key))
				{
					$key = "'".$key."'";
				}

				$output .= "<tr><td style='width:50%;color:#000;background-color:#ddd;padding:5px'>&#36;_GET[".$key."]&nbsp;&nbsp; </td><td style='width:50%;padding:5px;color:#cd6e00;font-weight:normal;background-color:#ddd;'>";
				if (is_array($val))
				{
					$output['&#36;_GET['. $key .']'] = "<pre>" . htmlspecialchars(stripslashes(print_r($val, true))) . "</pre>";
				}
				else
				{
					$output['&#36;_GET['. $key .']'] = htmlspecialchars(stripslashes($val));
				}
			}
		}

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Compile $_POST Data
	 *
	 * @return	string
	 */
	protected function _compile_post()
	{
		$output = array();
	
		if (count($_POST) == 0)
		{
			$output = $this->CI->lang->line('profiler_no_post');
		}
		else
		{
			foreach ($_POST as $key => $val)
			{
				if ( ! is_numeric($key))
				{
					$key = "'".$key."'";
				}

				if (is_array($val))
				{
					$output['&#36;_POST['. $key .']'] = '<pre>'. htmlspecialchars(stripslashes(print_r($val, TRUE))) . '</pre>';
				}
				else
				{
					$output['&#36;_POST['. $key .']'] = htmlspecialchars(stripslashes($val));
				}
			}
		}

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Show query string
	 *
	 * @return	string
	 */
	protected function _compile_uri_string()
	{
		if ($this->CI->uri->uri_string == '')
		{
			$output = $this->CI->lang->line('profiler_no_uri');
		}
		else
		{
			$output = $this->CI->uri->uri_string;
		}

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Show the controller and function that were called
	 *
	 * @return	string
	 */
	protected function _compile_controller_info()
	{
		$output = $this->CI->router->fetch_class()."/".$this->CI->router->fetch_method();

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Compile memory usage
	 *
	 * Display total used memory
	 *
	 * @return	string
	 */
	protected function _compile_memory_usage()
	{
		if (function_exists('memory_get_usage') && ($usage = memory_get_usage()) != '')
		{
			$output = number_format($usage) .' bytes';
		}
		else
		{
			$output = $this->CI->lang->line('profiler_no_memory_usage');
		}

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Compile header information
	 *
	 * Lists HTTP headers
	 *
	 * @return	string
	 */
	protected function _compile_http_headers()
	{
		$output = array();

		foreach (array('HTTP_ACCEPT', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_PORT', 'SERVER_NAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'HTTP_ACCEPT_LANGUAGE', 'SCRIPT_NAME', 'REQUEST_METHOD',' HTTP_HOST', 'REMOTE_HOST', 'CONTENT_TYPE', 'SERVER_PROTOCOL', 'QUERY_STRING', 'HTTP_ACCEPT_ENCODING', 'HTTP_X_FORWARDED_FOR') as $header)
		{
			$val = (isset($_SERVER[$header])) ? $_SERVER[$header] : '';
			$output[$header] =  $val;
		}

		return $output;
	}

	// --------------------------------------------------------------------

	/**
	 * Compile config information
	 *
	 * Lists developer config variables
	 *
	 * @return	string
	 */
	protected function _compile_config()
	{
		$output = array();

		foreach ($this->CI->config->config as $config=>$val)
		{
			if (is_array($val))
			{
				$val = print_r($val, TRUE);
			}

			$output[$config] = htmlspecialchars($val);
		}

		return $output;
	}

	// --------------------------------------------------------------------

	public function _compile_files() 
	{
		$files = get_included_files();
		
		sort($files);
		
		return $files;
	}
	
	//--------------------------------------------------------------------
	
	public function _compile_console() 
	{
		$logs = Console::get_logs();
		
		if ($logs['console']) 
		{
			foreach ($logs['console'] as $key => $log) 
			{
				if ($log['type'] == 'log') 
				{
					$logs['console'][$key]['data'] = print_r($log['data'], true);
				}
				elseif ($log['type'] == 'memory') 
				{
					$logs['console'][$key]['data'] = $this->get_file_size($log['data']);
				}
			}
		}
		
		//echo '<pre>'; print_r($logs); echo '</pre>';
		
		return $logs;
	}
	
	//--------------------------------------------------------------------
	
	function _compile_userdata()
	{
		$output = array();
	
		$compiled_userdata = $this->CI->session->all_userdata();
		
		if (count($compiled_userdata))
		{		
			foreach ($compiled_userdata as $key => $val)
			{
				if (is_numeric($key))
				{
					$output[$key] = "'$val'";
				}
				
				if (is_array($val) || is_object($val))
				{
					$output[$key] = htmlspecialchars(stripslashes(print_r($val, true)));
				}
				else
				{
					$output[$key] = htmlspecialchars(stripslashes($val));
				}
			}
		}
		
		return $output;
	}
	
	//--------------------------------------------------------------------
	
	public static function get_file_size($size, $retstring = null) {
        // adapted from code at http://aidanlister.com/repos/v/function.size_readable.php
	    $sizes = array('bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');

	    if ($retstring === null) { $retstring = '%01.2f %s'; }

		$lastsizestring = end($sizes);

		foreach ($sizes as $sizestring) {
	       	if ($size < 1024) { break; }
	           if ($sizestring != $lastsizestring) { $size /= 1024; }
	       }
	       if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional
	       return sprintf($retstring, $size, $sizestring);
	}
	
	//--------------------------------------------------------------------

	/**
	 * Run the Profiler
	 *
	 * @return	string
	 */
	public function run()
	{
		$this->CI->load->helper('language');
	
		$fields_displayed = 0;

		foreach ($this->_available_sections as $section)
		{
			if ($this->_compile_{$section} !== FALSE)
			{
				$func = "_compile_{$section}";
				$this->_sections[$section] = $this->{$func}();
				$fields_displayed++;				
			}
		}
		
		return $this->CI->load->view('profiler_template', array('sections' => $this->_sections), true);
	}

}

// END CI_Profiler class

//--------------------------------------------------------------------

/* End of file Profiler.php */
/* Location: ./system/libraries/Profiler.php */